{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from WindAlgo import * #引入回测框架\n",
    "import datetime\n",
    "from WindPy import *\n",
    "w.start()\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取建仓数据：等权重\n",
    "raw_data = pd.read_csv('data/stock_choosed.csv').drop(columns = 'Unnamed: 0')\n",
    "stock_choosed = dict([(k, \n",
    "                       dict([(m,\n",
    "                              1/raw_data[k].size) \\\n",
    "                             for m in raw_data[k].values]))\\\n",
    "                      for k in raw_data.columns])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取建仓数据：赋权重\n",
    "raw_data = pd.read_csv('data/test.csv')\n",
    "data = raw_data.set_index(['date','asset'])[['weight']]\n",
    "data['weight'] = data['weight']/100\n",
    "stock_choosed = dict([(pd.to_datetime(kk).strftime('%Y%m%d'),\n",
    "                       data.loc[kk].to_dict()['weight']) for kk in data.index.levels[0]])  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "有调仓的回测\n",
    "'''\n",
    "begdate = str(np.sort(list(stock_choosed.keys()))[0])\n",
    "enddate = datetime.now().strftime('%Y%m%d')\n",
    "#begdate = '20190801'\n",
    "#enddate = '20200925'\n",
    "\n",
    "# 获取投资的股票代码与权重\n",
    "stock_list = stock_choosed\n",
    "# 获取初始股票池\n",
    "code_list = list(stock_choosed[str(begdate)].keys())\n",
    "#code_list = list(stock_choosed['20171231'].keys())\n",
    "# 调仓时间\n",
    "close_time_list = list(stock_list.keys())\n",
    "open_time_list = list(stock_list.keys())\n",
    "close_time_list.sort(reverse = True)   # 倒序\n",
    "open_time_list.sort(reverse = True)   # 倒序\n",
    "# 删去多余的日期\n",
    "rudundantdatenum = (np.array(open_time_list)<begdate).astype('int').sum()-1\n",
    "if rudundantdatenum>0:\n",
    "    for i in range(rudundantdatenum):\n",
    "        open_time_list.pop()\n",
    "        close_time_list.pop()\n",
    "\n",
    "# 策略回测部分\n",
    "def initialize(context):\n",
    "    context.capital = 1000000\n",
    "    context.securities = code_list   # 初始股票池\n",
    "    context.benchmark='000905.SH'  #以中证500指数为基准\n",
    "    context.start_date = begdate\n",
    "    context.end_date = enddate\n",
    "    context.period = 'd'\n",
    "    context.stock_list = stock_list   # 全时段，分时间点的股票池\n",
    "\n",
    "def handle_data(bar_datetime, context, bar_data):  \n",
    "    #如设置计划任务，进行定期调仓时，handle_data函数不能省略，但可以用pass直接跳过\n",
    "    pass\n",
    "\n",
    "def my_schedule1(bar_datetime, context, bar_data): # 注意：schedule函数里不能加入新的参数\n",
    "    '''\n",
    "    清仓\n",
    "    '''\n",
    "    bar_datetime_str = bar_datetime.strftime('%Y%m%d')\n",
    "    if close_time_list:\n",
    "        if (bar_datetime_str >= close_time_list[-1]):\n",
    "            alter_time = close_time_list.pop()\n",
    "            #print(bar_datetime_str)        \n",
    "\n",
    "            code_list = list(context.stock_list[alter_time].keys())\n",
    "            bkt.change_securities(code_list)\n",
    "            context.securities = code_list  # 改变证券池\n",
    "\n",
    "            #做清仓处理\n",
    "            list_sell = list(bkt.query_position().get_field('code')) \n",
    "            for code in list_sell:\n",
    "                volumn = bkt.query_position()[code]['volume']    #找到每个code的持仓量 \n",
    "                res = bkt.order(code,volumn,'sell',price='close', volume_check=False)  # 卖出所有的股票  \n",
    "\n",
    "def my_schedule2(bar_datetime, context, bar_data):  #买入股票要在选股之后\n",
    "    '''\n",
    "    开仓\n",
    "    '''\n",
    "    bar_datetime_str = bar_datetime.strftime('%Y%m%d')\n",
    "    if open_time_list:\n",
    "        if (bar_datetime_str >= open_time_list[-1]):\n",
    "            alter_time = open_time_list.pop()\n",
    "            #print(\"my_schedule2: \",bar_datetime_str)\n",
    "            # 在单因子选股的结果中剔除没有行情的股票 \n",
    "            buy_code_list = list(set(context.securities)-(set(context.securities)-set(list(bar_data.get_field('code')))))  \n",
    "            stockinfo = context.stock_list[alter_time]     \n",
    "            for code in buy_code_list:\n",
    "                try:\n",
    "                    res = bkt.order_percent(code,stockinfo[code],'buy',price='close', volume_check=False)  \n",
    "                except:\n",
    "                    print(code)\n",
    "                    print(alter_time)\n",
    "                    print(bar_datetime_str)\n",
    "                    break\n",
    "\n",
    "bkt = BackTest(init_func = initialize, handle_data_func=handle_data)   #实例化回测对象\n",
    "bkt.schedule(my_schedule1, \"d\")         # 日频调整数据\n",
    "bkt.schedule(my_schedule2, \"d\")         # 日频调整数据\n",
    "res = bkt.run(show_progress=True)          #调用run()函数开始回测,show_progress可用于指定是否显示回测净值曲线图"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
